//
//  OPBoard.h
//  OPFramework
//
//  Created by malcom on 7/12/08.
//  Copyright 2008 __MyCompanyName__. All rights reserved.
//

/*!
    @class			OPBoard
    @abstract		This is the root class of your board.
    @discussion		You need to use this class in order to perform a connection with your choosed board. <br/>
					To init this object refer to <i>-initWithBoardAddress:withAuth:</i> method. <br/>
					Before init this file you can specify some configuration parameters. <br/>
					OPBoard can work in both synchronous and async mode (probability you will prefer async mode <br/>
					in a desktop environment and sync if you are using this in your iPhone). To set the mode you <br/>
					need to specify the BOOL property <i>_config_workAsAsync</i>. <br/>
					Remember: OPForum objects contains valid data and you not need to perform any request to server (in fact the board structure
					was downloaded in sync mode during the init process of OPBoard class.<br/>
					
					<B>NOTES ABOUT SYNC MODE:</B><br/>
					Sync mode is probability the easiest way to use OFAPI Objective-C framework. In this mode each created object <br/>
					(ie. OPUser, OPPosts and OPTopic) contains all required values each time you call it. This means that if a newly <br/>
					created object (that not contains any specific data but only the required class data as like 'forum id','user id' etc.) <br/>
					receive a request for a specific property your app need to wait that a request to forum server was performed and the result <br/>
					is received (this operation could take some time depending your connection).<br/> 
					The next time you will call this object OFAPI framework check if the cache is expired (you can specify max cache time in board <br/>
					preferences): if not it will return requested data immediately, otherwise another blocking request will be performed. <br/>
					<br/>
					<b>NOTES ABOUT ASYNC MODE:</b><BR/>
					The async mode is commonly used in desktop environment because it does not block main thread when it makes a request to server. <br/>
					We will now describe a common usage environment.<br/>
					Suppose you have a OPForum class and you need to download topics for a specif page using the async mode. <br/>
					Normally you just need to perform  <i>-getTopicsAtPage:usingCache:</i> method to the object but in this case you will not receive <br/>
					the NSArray with the OPTopic objects, but a nil value. <br/>
					However OFAPI framework will perform an async request to the server and will alerts you when the task was performed and data is updated. <br/>
					To receive notifications in your class you need to add it the listeners list of target OPForum class using <i>-addObjectAsListenerForMe</i> <br/>
					method. Your class must be conform to the <i>OPObject_AsyncResponse</i> protocol; you will receive the updated object (in this case choosed OPForum) <br/>
					in <i>dataUpdatedFor:forMethod:</i> method.<br/> 
					You can add more than a listeners for each class.<br/>
					Each ofapi class (not OPBoard, OPMembersCache) is based upon OPBaseObject class.<br/>
					
*/


#import <Foundation/Foundation.h>
#import "XMLRPC.h"

#import "OPAuthUser.h"
#import "OPBoardConfig.h"
#import "OPBoardStructure.h"
#import "OPMembersCache.h"
#import "OPPost.h"

@protocol OPBoard_AsyncResponse
- (void) opboard_init_boardNotSupported:(NSString *) _rootPath;
- (void) opboard_init_loginResult:(int) _res forBoard:(OPBoard *) _board;
- (void) opboard_init_configurationLoaded:(BOOL) _loaded forBoard:(OPBoard *) _board;
- (void) opboard_init_structureLoaded:(BOOL) _loaded forBoard:(OPBoard *) _board;
- (void) opboard_init_boardReady:(BOOL) _ready forBoard:(OPBoard *) _board;

@end

@class OPBaseObject;
@interface OPBoard : OPBaseObject {
	OPAuthUser			*obj_authUser;			// currently logged user
	OPBoardConfig		*obj_boardConfig;		// board configuration object
	OPBoardStructure	*obj_boardStructure;	// board structure
	NSURL				*obj_urlToOFAPILib;		// link to ofapi library php file
	NSString			*obj_boardRootPath;		// board root path
	OPMembersCache		*obj_membersCache;		// list of cached members of the forum
	
	BOOL				_config_workAsAsync;	// work in async mode (see documentation)
	int					_config_cacheValidTime;	// cache validation time (in seconds). When the cache expires data will be refreshed in synchronous mode
	
	XMLRPCResponse		*log_lastResponse;		// last request response
	NSObject <OPBoard_AsyncResponse> *_boardDelegate;
}

@property (readonly) OPBoardConfig		*obj_boardConfig;
@property (readonly) NSString			*obj_boardRootPath;
@property (readonly) OPBoardStructure	*obj_boardStructure;
@property (readonly) OPAuthUser			*obj_authUser;
@property (readonly) OPMembersCache		*obj_membersCache;
@property (assign) BOOL					_config_workAsAsync;
@property (assign) int					_config_cacheValidTime;

#pragma mark INIT
/*!
    @method     initWithBoardAddress:withAuth:
    @abstract   This method create a new board object using a supported ofapi board
    @discussion This is the root object of your board. You need to create this object before using other ofapi framework classes <br>
				You need to pass the root address of your forum in order to init this class (for example http://www.rietiforum.com/forum) <br>
				If your choosed board is compatible with ofapi library (-_checkOFAPICompatibility checked automatically) this init <br>
				return a valid object. Otherwise it will return an empty object. <br>
				If you get an empty object be sure to check the existence of: <br> <ul>
				<li> ofapi plugin (the ofapi folder must be located in your forum root path) </li> 
				<li> login data is correct (if you want to join as anonimous leave this object as nil) </li> 
				<li> structure of the forum was not downloaded for some reason </li> 
				<li> board configuration was not downloaded for some reason </li> </ul>
    @param      _url the root path of your board
	@param		_auth the OPAuthUser object with logging data (leave nil to enter as anonymous)
    @result     OPBoard object if joined successfully or nil if an error is occurred.
*/

- (id) initBoardAndLoadAsync:(BOOL) _asyncLoading address:(NSString *) _addr withAuth:(OPAuthUser *) _auth withDelegate:(NSObject <OPBoard_AsyncResponse> *) _delegate;

- (id) _initWithBoardAddress:(NSString *) _url withAuth:(OPAuthUser *) _auth withDelegate:(NSObject <OPBoard_AsyncResponse> *) _delegate;
- (id) _initAsyncWithBoardAddress:(NSString *) _url withAuth:(OPAuthUser *) _auth withDelegate:(NSObject <OPBoard_AsyncResponse> *) _delegate;

#pragma mark ACCESSOR METHODS

/*!
    @method     getPostWithID:forceLoad:
    @abstract   Return a loaded post from cache or download it from server.
    @discussion You can use this method if you need to retrive a specific post. It will perform a local search in board's cache
				and if there is not any result, when _load is YES it will make a sync request to server in order to get it.
	@param		_uid	target post id you want to get
	@param		_load	if true when a local search fails, ofapi will make a sync remote request
*/

- (OPPost *) getPostWithID:(NSNumber *) _uid forceLoad:(BOOL) _load;

#pragma mark XML RPC METHODS
- (XMLRPCResponse *) _executeRequestMethodNamed:(NSString *) _method withParams:(NSArray *) _params;
- (XMLRPCResponse *) _executeRequestMethodNamed:(NSString *) _method withParams:(NSArray *) _params attachAuthData:(NSArray *) _auth;
- (XMLRPCResponse *) _executeRequestMethodNamed:(NSString *) _method withParams:(NSArray *) _params attachAuthData:(NSArray *) _auth asyncResponse:(id <XMLRPC_AsyncResponse>) _asResp;
- (void) _executeAsyncMethodNamed:(NSString *) _named withParams:(NSArray *) _params attachAuthData:(NSArray*) _auth responseObject:(id <XMLRPC_AsyncResponse>) _resp;
- (void) _executeAsyncMethodNamed:(NSString *) _named withParams:(NSArray *) _params responseObject:(id <XMLRPC_AsyncResponse>) _resp;

#pragma mark PRIVATE METHODS
- (NSURL *) _checkOFAPICompatibility:(NSString *) _rootPathAddress;
- (BOOL) _testLoginToBoard:(OPAuthUser *) _user;
- (void) _checkLoginResult:(NSArray *) _result;

@end
